﻿using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Windows;
using Caliburn.Micro;
using Caliburn.Micro.Extensions;
using CoProjectDF.Repository;
using CoProjectModel;
using Coproject.Events;
using Coproject.Framework;
using Coproject.ViewModels.Interfaces;
using Action = System.Action;

namespace Coproject.ViewModels
{
    [Export(typeof(IToDoItemViewModel))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ToDoItemViewModel : Screen, IToDoItemViewModel
    {
        private readonly IToDoItemRepository _repository;
        private bool _isReadOnly;
        private ToDoItem _item;

        [ImportingConstructor]
        public ToDoItemViewModel(IEventAggregator eventAggregator, IToDoItemRepository repository)
        {
            EventAggregator = eventAggregator;
            DisplayName = "To Do";
            Description = "To-do lists";
            _repository = repository;
            eventAggregator.Subscribe(this);
        }

        [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
        public IBusyWatcher Busy { get; set; }

        public string Description { get; private set; }

        public IEventAggregator EventAggregator { get; set; }

        public bool IsReadOnly
        {
            get { return _isReadOnly; }
            set
            {
                _isReadOnly = value;
                NotifyOfPropertyChange(() => IsReadOnly);
                NotifyOfPropertyChange(() => CanEdit);
                NotifyOfPropertyChange(() => CanCancel);
            }
        }

        public bool CanEdit
        {
            get { return IsReadOnly; }
        }

        public bool CanCancel
        {
            get { return !IsReadOnly; }
        }

        public bool CanSave
        {
            get { return true; }
        }

        #region IToDoItemViewModel Members

        public ToDoItem Item
        {
            get { return _item; }
            private set
            {
                _item = value;
                NotifyOfPropertyChange(() => Item);
            }
        }

        public IResult GetToDoItem(int toDoItemID, Action onSuccess, Action<Exception> onFail)
        {
            IsReadOnly = true;

            return CoroutineFns.AsResult(
                () => _repository.FindToDoItemByID(toDoItemID,
                                                   (r) =>
                                                   {
                                                       Item = r;
                                                       Item.PropertyChanged +=
                                                           (s, e) => NotifyOfPropertyChange(() => CanSave);
                                                       if (onSuccess != null)
                                                           onSuccess();
                                                   }, onFail));
        }

        #endregion

        public ToDoItemViewModel Start()
        {
            _repository.GetFirstItem((r) => Item = r);
            return this;
        }

        public void Edit()
        {
            IsReadOnly = false;
        }

        public void Cancel()
        {
            (Item as IEditableObject).CancelEdit();
            IsReadOnly = true;

            #region Fix DataForm bug

            IsReadOnly = false;
            IsReadOnly = true;

            #endregion
        }

        public void Save()
        {
            (Item as IEditableObject).EndEdit();
            IsReadOnly = true;

            #region Fix DataForm bug

            IsReadOnly = false;
            IsReadOnly = true;

            #endregion

            Busy.AddWatch();
            _repository.Save(() =>
                                 {
                                     EventAggregator.Publish(new ToDoItemUpdatedEvent(Item.ToDoItemID));
                                     Busy.RemoveWatch();
                                 },
                             (e) =>
                             {
                                 Busy.RemoveWatch();
                                 if (e != null)
                                 {
                                     MessageBox.Show(e.Message, "System Error", MessageBoxButton.OK);
                                 }
                             });
        }

        public override void CanClose(Action<bool> callback)
        {
            if (Item.EntityAspect.HasChanges())
            {
                MessageBoxResult result = MessageBox.Show("Current item was not saved. Do you really want to close it?",
                                                          "Coproject", MessageBoxButton.OKCancel);
                callback(result == MessageBoxResult.OK);
            }
            else
            {
                callback(true);
            }
        }

        protected override void OnDeactivate(bool isClosing)
        {
            if (isClosing && CanCancel)
            {
                Cancel();
            }
        }
    }
}